#include "pixel_data.h"
#include "my_console.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

// 动态分配二维数组
Array2D* allocate_2d_array(size_t width, size_t height) {
    // 分配结构体
    Array2D* array = (Array2D*)malloc(sizeof(Array2D));
    if (!array) {
        perror("Failed to allocate memory for Array2D");
        return NULL;
    }

    // 初始化宽高
    array->width = width;
    array->height = height;

    // 分配行指针数组
    array->data = (u32**)malloc(height * sizeof(u32*));
    if (!array->data) {
        perror("Failed to allocate memory for row pointers");
        free(array);
        return NULL;
    }

    // 分配每行的数据
    for (size_t i = 0; i < height; i++) {
        array->data[i] = (u32*)malloc(width * sizeof(u32));
        if (!array->data[i]) {
            perror("Failed to allocate memory for row data");
            // 如果某一行分配失败，释放之前分配的内存
            for (size_t j = 0; j < i; j++) {
                free(array->data[j]);
            }
            free(array->data);
            free(array);
            return NULL;
        }
    }

    // 初始化数组内容为 0
    for (size_t i = 0; i < height; i++) {
        memset(array->data[i], 0, width * sizeof(u32));
    }

    return array;
}

// 释放二维数组
void free_2d_array(Array2D* array) {
    if (!array) return;

    // 释放每行的数据
    for (size_t i = 0; i < array->height; i++) {
        free(array->data[i]);
    }

    // 释放行指针数组
    free(array->data);

    // 释放结构体本身
    free(array);
}

// 给定坐标赋值
int set_value(Array2D* array, const Coordinate coord, u32 value) {
    if (!array || coord.x >= array->width || coord.y >= array->height) {
        fprintf(stderr, "Error: Coordinates (%zu, %zu) out of bounds (width=%zu, height=%zu)\n",
                coord.x, coord.y, array->width, array->height);
        return -1; // 返回错误码
    }
    array->data[coord.y][coord.x] = value;
    return 0; // 成功
}

// 读取指定坐标的值
u32 get_value(const Array2D* array, const Coordinate coord) {
    if (!array || coord.x >= array->width || coord.y >= array->height) {
        fprintf(stderr, "Error: Coordinates (%zu, %zu) out of bounds (width=%zu, height=%zu)\n",
                coord.x, coord.y, array->width, array->height);
        return 0; // 返回默认值 0
    }
    return array->data[coord.y][coord.x];
}

// 清除数组内容（将所有元素设置为 0）
void clear_array(Array2D* array) {
    if (!array) return;

    for (size_t i = 0; i < array->height; i++) {
        memset(array->data[i], 0, array->width * sizeof(u32));
    }
}

// 将所有数据输出到文件
int save_to_file(const Array2D* array, const char* filename) {
    if (!array) {
        fprintf(stderr, "Error: Array is NULL\n");
        return -1; // 返回错误码
    }

    FILE* file = fopen(filename, "wb");
    if (!file) {
        perror("Failed to open file for writing");
        return -1; // 返回错误码
    }

    // 写入宽度和高度信息
    fwrite(&array->width, sizeof(size_t), 1, file);
    fwrite(&array->height, sizeof(size_t), 1, file);

    // 写入数组数据
    for (size_t i = 0; i < array->height; i++) {
        fwrite(array->data[i], sizeof(u32), array->width, file);
    }

    fclose(file);
    return 0; // 成功
}

// 从文件中读取二维数组数据
Array2D* load_from_file(const char* filename) {
    FILE* file = fopen(filename, "rb");
    if (!file) {
        perror("Failed to open file for reading");
        return NULL;
    }

    // 读取宽度和高度
    size_t width, height;
    fread(&width, sizeof(size_t), 1, file);
    fread(&height, sizeof(size_t), 1, file);

    // 分配二维数组
    Array2D* array = allocate_2d_array(width, height);
    if (!array) {
        fclose(file);
        return NULL;
    }

    // 读取数组数据
    for (size_t i = 0; i < height; i++) {
        fread(array->data[i], sizeof(u32), width, file);
    }

    fclose(file);
    return array;
}

// 新增函数：按行打印数组，每8个点位合成一个字节（十六进制）
void print_array_as_hex(const Array2D* array, uint16_t x, uint16_t yp) {
    if (!array) {
        fprintf(stderr, "Error: Array is NULL\n");
        return;
    }
    for (size_t y = 0; y < array->height; y++) {
        MoveCursorTo(x + 2, yp + y);
        uint8_t byte = 0;
        int bit_count = 0;
        for (size_t x = 0; x < array->width; x++) {
            u32 value = array->data[y][x];
            byte <<= 1; // 左移一位，腾出最低位
            if (value != 0) {
                byte |= 1; // 非零值设为1
            }
            bit_count++;
            if (bit_count == 8) {
                printf("0x%02X, ", byte);
                byte = 0;
                bit_count = 0;
            }
        }
        // 处理剩余不足8位的情况
        if (bit_count > 0) {
            byte <<= (8 - bit_count); // 左移补零
            printf("0x%02X,", byte);
        }
        printf("\n");
    }
}

// 新增函数：将数组保存为RGB图像文件
int save_as_image(const Array2D* array, const char* filename) {
    if (!array) {
        fprintf(stderr, "Error: Array is NULL\n");
        return -1;
    }
    FILE* file = fopen(filename, "wb");
    if (!file) {
        perror("Failed to open file for writing image");
        return -1;
    }
    for (size_t y = 0; y < array->height; y++) {
        for (size_t x = 0; x < array->width; x++) {
            u32 value = array->data[y][x];
            uint8_t r = (value >> 16) & 0xFF; // 提取红色分量
            uint8_t g = (value >> 8)  & 0xFF; // 提取绿色分量
            uint8_t b = value & 0xFF;         // 提取蓝色分量
            if (fwrite(&r, sizeof(uint8_t), 1, file) != 1 ||
                fwrite(&g, sizeof(uint8_t), 1, file) != 1 ||
                fwrite(&b, sizeof(uint8_t), 1, file) != 1) {
                perror("Failed to write RGB data");
                fclose(file);
                return -1;
            }
        }
    }
    fclose(file);
    return 0;
}

// 主函数测试
int mainTest() {
    size_t width = 9, height = 16;

    // 动态分配二维数组
    Array2D* array = allocate_2d_array(width, height);
    if (!array) {
        fprintf(stderr, "Failed to allocate 2D array\n");
        return EXIT_FAILURE;
    }

    // 测试赋值
    Coordinate coord1 = {0, 0};
    Coordinate coord2 = {1, 1};
    Coordinate coord3 = {2, 2};

    set_value(array, coord1, 0x00FF0000); // 红色
    set_value(array, coord2, 0x0000FF00); // 绿色
    set_value(array, coord3, 0x000000FF); // 蓝色

    Coordinate coord4 = {width - 1, height - 1};
    set_value(array, coord4, 0x00FFF1E1);

    // 测试读取
    printf("Value at (%zu, %zu): %u\n", coord1.x, coord1.y, get_value(array, coord1)); // 输出 10
    printf("Value at (%zu, %zu): %u\n", coord2.x, coord2.y, get_value(array, coord2)); // 输出 20
    printf("Value at (%zu, %zu): %u\n", coord3.x, coord3.y, get_value(array, coord3)); // 输出 30

    // 输出数组内容到文件
    const char* filename = "output.bin";
    if (save_to_file(array, filename) != 0) {
        fprintf(stderr, "Failed to save array to file\n");
    } else {
        printf("Array saved to file successfully.\n");
    }

    const char* image_filename = "output.rgb";
    save_as_image(array, image_filename);

    print_array_as_hex(array, 0, 0);
    // 清除数组内容
    // clear_array(array);

    // // 从文件中读取数组
    // Array2D* loaded_array = load_from_file(filename);
    // if (!loaded_array) {
    //     fprintf(stderr, "Failed to load array from file\n");
    //     free_2d_array(array);
    //     return EXIT_FAILURE;
    // }

    // // 测试读取加载的数据
    // printf("Loaded Value at (%zu, %zu): %u\n", coord1.x, coord1.y, get_value(loaded_array, coord1)); // 输出 10
    // printf("Loaded Value at (%zu, %zu): %u\n", coord2.x, coord2.y, get_value(loaded_array, coord2)); // 输出 20
    // printf("Loaded Value at (%zu, %zu): %u\n", coord3.x, coord3.y, get_value(loaded_array, coord3)); // 输出 30

    // 释放内存
    free_2d_array(array);
    // free_2d_array(loaded_array);

    return EXIT_SUCCESS;
}